package struts.action;

import dao.DAOVocabulario;
import dao.Hibernate;
import java.net.URL;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import logica.util.TratamientoCadena;
import negocio.Documento;
import negocio.Feed;
import negocio.Posteo;
import negocio.Vocabulario;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import rss.Article;
import rss.ArticleLoadedListener;
import rss.FeedPoller;

public class CrawlerAction extends org.apache.struts.action.Action {

    public static boolean corriendo;
    //private CrawlerHilo hilo;
    private double tiempoBusqueda = 0;
    private double startTime = 0;
    private FeedPoller feedPoller;

    /**
     * This is the action called from the Struts framework.
     * @param mapping The ActionMapping used to select this instance.
     * @param form The optional ActionForm bean for this request.
     * @param request The HTTP Request we are processing.
     * @param response The HTTP Response we are processing.
     * @throws java.lang.Exception
     * @return
     */
    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        if (isCancelled(request)) {
            if (feedPoller!=null) {
                feedPoller.setFinish(true);
            }
            return mapping.findForward("successCrawler");
        }

        feedPoller.setFinish(false);
        List<Feed> listaFeeds = dao.DAOFeed.findAll();
        Vector<URL> urlVector = new Vector<URL>();
        for (int i = 0; i < listaFeeds.size(); i++) {
            Feed feed = (Feed) listaFeeds.get(i);
            urlVector.add(new URL(feed.getUrl()));
        }

        if (feedPoller == null) {
            feedPoller = new FeedPoller(urlVector, 300000, new ArticleLoadedListener() {

                public void notify(Article article) {
                    Documento documento = new Documento();
                    documento.setTitulo(article.getTitle());
                    documento.setDescripcion(article.getPlainDescription());
                    documento.setTitulo(article.getTitle());
                    documento.setUrl(article.getLink().toString());

                    dao.DAODocumento.guardarDocumento(documento);
                    indexarDocumento(documento);

                }

                public void notify(Exception exception) {
                    exception.printStackTrace();
                }

                public void indexarDocumento(Documento documento) {
                    Hashtable<String, Posteo> tablaPosteoTemporal = new Hashtable<String, Posteo>();

                    StringBuilder sbCadenaAIndexar = new StringBuilder();
                    sbCadenaAIndexar.append(documento.getTitulo());
                    sbCadenaAIndexar.append(" ");
                    sbCadenaAIndexar.append(documento.getDescripcion());

                    String cadenaAIndexar = TratamientoCadena.tratarTextoIndexacion(sbCadenaAIndexar.toString());

                    StringTokenizer tokenizerPalabras = new StringTokenizer(cadenaAIndexar); // se divide el texto en palabras
                    // se procede a trabajar con cada palabra del documento en un ciclo while
                    while (tokenizerPalabras.hasMoreElements()) {
                        String palabra = tokenizerPalabras.nextElement().toString();

                        /* Se verifica si es una palabra vacia. En caso positivo no debemos trabajar con esa palabra */

                        if (!TratamientoCadena.esPalabraVacia(palabra)) {

                            /* Por cada palabra del documento se debe crear un posteo para incluirlo en la lista
                             * de posteo del vocabulario. Para ello se usa el metodo crearPosteo. El nuevo posteo
                             * se agrega en tablaPosteoTemporal y se puede obtener realizando un get con la palabra
                             * del posteo. */
                            crearPosteo(tablaPosteoTemporal, palabra, documento);

                            /* Se debe verificar si el Vocabulario en memoria contiene a la palabra que se esta analizando.
                             * En caso positivo se obtiene el objeto Vocabulario correspondiente a la palabra.
                             * En caso negativo se debe crear un nuevo objeto Vocabulario y agregarlo al hashVocabulario que
                             * esta en memoria.
                             */

                            if (DAOVocabulario.hashVocabulario.containsKey(palabra)) {
                                Vocabulario vocabulario = DAOVocabulario.hashVocabulario.get(palabra);
                                Posteo posteo = tablaPosteoTemporal.get(palabra);

                                // Se actualizan los valores de la frecuencia maxima del vocabulario
                                if (posteo.getFrecuencia() > vocabulario.getFrecuenciaMaxima()) {
                                    vocabulario.setFrecuenciaMaxima(posteo.getFrecuencia());
                                }

                                /* Se debe verificar si la lista de posteo del vocabulario contiene al posteo que
                                 * se esta analizando. Por ejemplo, si un documento tiene dos veces una palabra, entonces
                                 * se debe crear un solo posteo con frecuencia dos, y NO dos posteos.
                                 * En el caso que no este el posteo en el vocabulario, se lo debe agregar en el listado de posteos
                                 * del vocabulario.
                                 */
                                if (!vocabulario.getListaPosteo().contains(posteo)) {
                                    vocabulario.getListaPosteo().add(posteo);

                                    /* Para determinar la cantidad de documentos que contienen una palabra o vocabulario,
                                     * simplemente obtenemos el tamanio de la lista de posteo del vocabulario, ya que cada
                                     * posteo se corresponde con una o varias coincidencias del vocabulario por documento.
                                     */
                                    vocabulario.setCantidadDocumentos((short) vocabulario.getListaPosteo().size());
                                }
                                Hibernate.saveOrUpdateObjeto(posteo);
                                Hibernate.saveOrUpdateObjeto(vocabulario);
                            } 
                            else
                            {
                                Posteo posteo = tablaPosteoTemporal.get(palabra);

                                Vocabulario vocabulario = new Vocabulario();
                                vocabulario.setPalabra(palabra);
                                vocabulario.setCantidadDocumentos((short) 1);
                                vocabulario.setFrecuenciaMaxima(posteo.getFrecuencia());
                                vocabulario.getListaPosteo().add(posteo);
                                Hibernate.saveOrUpdateObjeto(posteo);
                                Hibernate.saveOrUpdateObjeto(vocabulario);
                                DAOVocabulario.hashVocabulario.put(palabra, vocabulario);
                            }
                        }
                    }
                    //DAOVocabulario.saveOrUpdateHashVocabulario();
                }

                private void crearPosteo(Hashtable<String, Posteo> tablaPosteoTemporal, String palabra, Documento documento) {
                    //antes buscar si existe la palabra antes de guardarla
                    if (!tablaPosteoTemporal.containsKey(palabra)) {
                        //primera vez que entra una palabra le asigno el valor 1
                        Posteo posteo = new Posteo(documento, (short) 1);
                        tablaPosteoTemporal.put(palabra, posteo);
                    } else {
                        Posteo posteo = tablaPosteoTemporal.get(palabra);
                        short frecuencia = posteo.getFrecuencia();
                        frecuencia++;
                        posteo.setFrecuencia(frecuencia);
                    }
                }
            });

            Thread poolThread = new Thread(feedPoller);
            poolThread.start();
        }

        return mapping.findForward("successCrawler");
    }
}
